﻿using System;
using System.Collections.Generic;
using OpenTK;
using System.Linq;

namespace Mono.Rift.Core.Graphics
{
	public class Model : Node
	{
		public List<Vertex> Vertices { get; set; }
		public List<int> Indeces { get; set; }
		public PrimitiveTypes PrimitiveType { get; set; }
		public Fill Fill { get; set; }
		public Buffer VertexBuffer { get; set; }
		public Buffer IndexBuffer { get; set; }

		public bool Visible {
			get;
			set;
		}
		public bool IsCollisionModel {
			get;
			set;
		}

		public Model (PrimitiveTypes t = PrimitiveTypes.Triangles)
		{
			PrimitiveType = t;
			Fill = null;
			Visible = true;
			Vertices = new List<Vertex> ();
			Indeces = new List<int> ();
			/*
			VertexBuffer = new Buffer ();
			IndexBuffer = new Buffer ();
			*/
		}

		public override void clearRenderer ()
		{
			VertexBuffer.clear ();
			IndexBuffer.clear ();
		}

		public uint getNextVertexIndex()
		{
			return (uint)Vertices.Count;
		}

		public int addVertex(Vertex v)
		{
			var index = Vertices.Count;
			Vertices.Add (v);
			return index;
		}

		public uint addVertex(Vector3 v, Color c, float u_ = 0, float v_ = 0)
		{
			return (uint)addVertex (new Vertex (v, c, u_, v_));
		}

		public uint addVertex(float x, float y, float z, Color c, float u, float v)
		{
			return (uint)addVertex (new Vertex (new Vector3 (x, y, z), c, u, v));
		}

		public void addLine(int a, int b)
		{
			Indeces.Add (a);
			Indeces.Add (b);
		}

		public void addLine(Vertex a, Vertex b)
		{
			addLine(addVertex(a), addVertex(b));
		}

		public void addTriangle(uint a, uint b, uint c)
		{
			Indeces.Add ((int)a);
			Indeces.Add ((int)b);
			Indeces.Add ((int)c);
		}

		static int[,] _cubeIndices =
		{
			{ 0, 1, 3 },
			{ 3, 1, 2 },

			{ 5, 4, 6 },
			{ 6, 4, 7 },

			{ 8, 9, 11 },
			{ 11, 9, 10 },

			{ 13, 12, 14 },
			{ 14, 12, 15 },

			{ 16, 17, 19 },
			{ 19, 17, 18 },

			{ 21, 20, 22 },
			{ 22, 20, 23}
		};

		public void addSolidColorBox(float x1, float y1, float z1, float x2, float y2, float z2, Color c)
		{
			float t;
			if (x1 > x2) {
				t = x1;
				x1 = x2;
				x2 = t;
			}
			if (y1 > y2) {
				t = y1;
				y1 = y2;
				y2 = t;
			}
			if (z1 > z2) {
				t = z1;
				z1 = z2;
				z2 = t;
			}

			var cubeVertices =  new [,] {
				{ new Vector3(x1, y2, z1), new Vector3(z1, x1, 0), new Vector3(0, 1, 0) },
				{ new Vector3(x2, y2, z1), new Vector3(z1, x2, 0), new Vector3(0, 1, 0) },
				{ new Vector3(x2, y2, z2), new Vector3(z2, x2, 0), new Vector3(0, 1, 0) },
				{ new Vector3(x1, y2, z2), new Vector3(z2, x1, 0), new Vector3(0, 1, 0) },

				{ new Vector3(x1, y1, z1), new Vector3(z1, x1, 0), new Vector3(0, -1, 0) },
				{ new Vector3(x2, y1, z1), new Vector3(z1, x2, 0), new Vector3(0, -1, 0) },
				{ new Vector3(x2, y1, z2), new Vector3(z2, x2, 0), new Vector3(0, -1, 0) },
				{ new Vector3(x1, y1, z2), new Vector3(z2, x1, 0), new Vector3(0, -1, 0) },

				{ new Vector3(x1, y1, z2), new Vector3(z2, y1, 0), new Vector3(-1, 0, 0) },
				{ new Vector3(x1, y1, z1), new Vector3(z1, y1, 0), new Vector3(-1, 0, 0) },
				{ new Vector3(x1, y2, z1), new Vector3(z1, y2, 0), new Vector3(-1, 0, 0) },
				{ new Vector3(x1, y2, z2), new Vector3(z2, y2, 0), new Vector3(-1, 0, 0) },

				{ new Vector3(x2, y1, z2), new Vector3(z2, y1, 0), new Vector3(1, 0, 0) },
				{ new Vector3(x2, y1, z1), new Vector3(z1, y1, 0), new Vector3(1, 0, 0) },
				{ new Vector3(x2, y2, z1), new Vector3(z1, y2, 0), new Vector3(1, 0, 0) },
				{ new Vector3(x2, y2, z2), new Vector3(z2, y2, 0), new Vector3(1, 0, 0) },

				{ new Vector3(x1, y1, z1), new Vector3(x1, y1, 0), new Vector3(0, 0, -1) },
				{ new Vector3(x2, y1, z1), new Vector3(x2, y1, 0), new Vector3(0, 0, -1) },
				{ new Vector3(x2, y2, z1), new Vector3(x2, y2, 0), new Vector3(0, 0, -1) },
				{ new Vector3(x1, y2, z1), new Vector3(x1, y2, 0), new Vector3(0, 0, -1) },

				{ new Vector3(x1, y1, z2), new Vector3(x1, y1, 0), new Vector3(0, 0, 1) },
				{ new Vector3(x2, y1, z2), new Vector3(x2, y1, 0), new Vector3(0, 0, 1) },
				{ new Vector3(x2, y2, z2), new Vector3(x2, y2, 0), new Vector3(0, 0, 1) },
				{ new Vector3(x1, y2, z2), new Vector3(x1, y2, 0), new Vector3(0, 0, 1) },

			};

			var startIndex = getNextVertexIndex ();

			var cvc = cubeVertices.Length;
			var cic = _cubeIndices.Length;

			for (var v = 0; v < cvc; v++) {
				addVertex (new Vertex (cubeVertices [v, 0], c,cubeVertices [v, 1].X, cubeVertices [v, 1].Y, cubeVertices [v, 2]));
			}

			for (var i = 0; i < cic; i++) {
				addTriangle (
					(uint)(_cubeIndices [i, 0] + startIndex),
					(uint)(_cubeIndices [i, 1] + startIndex),
					(uint)(_cubeIndices [i, 2] + startIndex));
			}
		}

		public static Model createAxisFaceColorBox(float x1, float x2, Color xcolor, float y1, float y2, Color ycolor, float z1, float z2, Color zcolor)
		{
			float t;
			if (x1 > x2) {
				t = x1;
				x1 = x2;
				x2 = t;
			}
			if (y1 > y2) {
				t = y1;
				y1 = y2;
				y2 = t;
			}
			if (z1 > z2) {
				t = z1;
				z1 = z2;
				z2 = t;
			}

			var box = new Model ();
			uint startIndex = 0;

			startIndex = box.addVertex (new Vector3(x1, y2, z1), ycolor);
			box.addVertex (new Vector3(x2, y2, z1), ycolor);
			box.addVertex (new Vector3(x2, y2, z2), ycolor);
			box.addVertex (new Vector3(x1, y2, z2), ycolor);

			box.addVertex (new Vector3(x1, y1, z1), ycolor);
			box.addVertex (new Vector3(x2, y1, z1), ycolor);
			box.addVertex (new Vector3(x2, y1, z2), ycolor);
			box.addVertex (new Vector3(x1, y1, z2), ycolor);

			box.addVertex (new Vector3(x1, y1, z2), xcolor);
			box.addVertex (new Vector3(x1, y1, z1), xcolor);
			box.addVertex (new Vector3(x1, y2, z1), xcolor);
			box.addVertex (new Vector3(x1, y2, z2), xcolor);

			box.addVertex (new Vector3(x2, y1, z2), xcolor);
			box.addVertex (new Vector3(x2, y1, z1), xcolor);
			box.addVertex (new Vector3(x2, y2, z1), xcolor);
			box.addVertex (new Vector3(x2, y2, z2), xcolor);

			box.addVertex (new Vector3(x1, y1, z1), zcolor);
			box.addVertex (new Vector3(x2, y1, z1), zcolor);
			box.addVertex (new Vector3(x2, y2, z1), zcolor);
			box.addVertex (new Vector3(x1, y2, z1), zcolor);

			box.addVertex (new Vector3(x1, y1, z2), zcolor);
			box.addVertex (new Vector3(x2, y1, z2), zcolor);
			box.addVertex (new Vector3(x2, y2, z2), zcolor);
			box.addVertex (new Vector3(x1, y2, z2), zcolor);

			var cic = _cubeIndices.Length;

			for (var i = 0; i < cic; i++) {
				box.addTriangle (
					(uint)_cubeIndices [i, 0] + startIndex, 
					(uint)_cubeIndices [i, 1] + startIndex, 
					(uint)_cubeIndices [i, 2] + startIndex);
			}

			return box;
		}

		public override void render (Matrix4 ltw, RenderDevice device)
		{
			if (Visible) {
				var m = Matrix4.Mult (ltw, Mat);
				device.render (m, this);
			}
		}
	}
}

